package cytargetlinker.conversion;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

import cytargetlinker.conversion.ArgsParser.AFilesIn;
import cytargetlinker.conversion.ArgsParser.AFilesOut;
import cytargetlinker.conversion.ArgsParser.AHelp;
import cytargetlinker.conversion.ArgsParser.GraphBuilder;
import cytargetlinker.conversion.graph.Graph;
import cytargetlinker.conversion.graph.Graph.Edge;
import cytargetlinker.conversion.graph.Graph.Node;

/**
 * Converts miRNA target text files from MiRTarBase to a XGMML or GML network.
 * 
 * The input files for this script can be downloaded here:
 * http://mirtarbase.mbc.nctu.edu.tw/php/download.php (under "Catatolog by Species").
 * 
 * @author Thomas, Pooja, Naime, Tina
 */
public class MirTarBase {
	private final static Logger log = Logger.getLogger(MirTarBase.class.getName());
	
	public static void main(String argv[]) throws Exception {
		
		Args pargs = ArgsParser.parse(argv, Args.class);
		new MiRTarBaseConverter(pargs);
		
	}
	
	public static class MiRTarBaseConverter {
		
		private Graph graph;
		private Map<String, Integer> index;
		private Map<String, List<String>> edges;
		
		private List<String> foundConnections;
		
		public MiRTarBaseConverter(Args pargs) throws Exception {
			log.info("conversion of MiRTarBase file started ...\n");
			ArgsParser.convertAndWrite(pargs, pargs, new GraphBuilder() {
				public Graph buildGraph(File in) throws Exception {
					return importMiRecords(in);
				}
			});
			log.info("conversion of MiRTarBase file finalized.\n");
		}

		public Graph importMiRecords(File input) throws IOException {
			foundConnections = new ArrayList<String>();
			
			BufferedReader br = new BufferedReader(new FileReader(input));
			
			String[] header = br.readLine().split("\t");
			index = new HashMap<String, Integer>();
			for(int i = 0; i < header.length; i++) {
				index.put(header[i], i);
			}
			
			graph = new Graph();
			setNetworkAttributes(input);
			
			//Load each line into memory
			
			String line = null;
			List<String[]> rows = new ArrayList<String[]>();
			while((line = br.readLine()) != null) {
				String [] str = line.split("\t");
				if(str[index.get("Species (Target Gene)")].equals("Homo sapiens")) {
					rows.add(line.split("\t", header.length));
				}
			}
			
			edges = new HashMap<String, List<String>>();
			for(String[] r : rows) {
				
				String id = r[index.get("Target Gene (Entrez ID)")];

				Node n = graph.addNode(id);
				n.setAttribute("EntrezGene", id);
				n.setAttribute("label", r[index.get("Target Gene")]);
				n.setAttribute("name", r[index.get("Target Gene")]);
				n.setAttribute("Organism", r[index.get("Species (Target Gene)")]);
							
				String mirna = r[index.get("miRNA")];
				Node mirnaNode = graph.addNode(mirna);
				mirnaNode.setAttribute("miRNA", mirna);
				mirnaNode.setAttribute("label", mirna);
				mirnaNode.setAttribute("name", mirna);
				mirnaNode.setAttribute("Organism", r[index.get("Species (miRNA)")]);
						
				addEdge(id, mirna, r);
			}
			
			printResults(false);
			
			return graph;
		}
		
		private void printResults(boolean printDetails) {
			
			System.out.println("found " + foundConnections.size()+ " miRNA-gene interactions.\n");
			
			if(printDetails) {
				System.out.println("------------------------\n");
			
				System.out.println("FOUND CONNECTIONS " + foundConnections.size());
				for(String str : foundConnections) {
					System.out.println(str);
				}	
				
				System.out.println("\n------------------------");
				System.out.println("found " + foundConnections.size()+ " miRNA-gene interactions.\n");
			}
		}
		
		private void setNetworkAttributes(File input) {
			graph.setTitle("MirTarBase");
			graph.setAttribute(CommonAttributes.DATABASE.getName(), "MirTarBase");
			graph.setAttribute(CommonAttributes.TYPE.getName(), "miRNA targets");
			graph.setAttribute(CommonAttributes.SOURCE_FILE.getName(), input.getName());
			graph.setAttribute(CommonAttributes.TARGET_ID_ATTRIBUTE.getName(), "EntrezGene");
			graph.setAttribute(CommonAttributes.TARGET_DATASOURCE.getName(), "Entrez Gene");
			graph.setAttribute(CommonAttributes.SOURCE_ID_ATTRIBUTE.getName(), "miRNA");
			graph.setAttribute(CommonAttributes.SOURCE_DATASOURCE.getName(), "");
			graph.setAttribute(CommonAttributes.SOURCE_TYPE.getName(), "mirna");
			graph.setAttribute(CommonAttributes.TARGET_TYPE.getName(), "gene");
		}
		
		private Integer countEdges = 0;
		
		private void addEdge(String gene, String mirna, String [] r) {
			
			if(edges.containsKey(gene)) {
				if(!edges.get(gene).contains(mirna)) {
					Edge e = graph.addEdge("" + countEdges, graph.getNode(mirna),graph.getNode(gene));
					e.setAttribute("experiments", r[index.get("Experiments")]);
					e.setAttribute("supportType", r[index.get("Support Type")]);
					e.setAttribute("referenceID", r[index.get("References (PMID)")]);
					edges.get(gene).add(mirna);
					foundConnections.add(gene + "\t" + mirna);
					countEdges++;
				}
			} else {
				
				Edge e = graph.addEdge("" + countEdges, graph.getNode(mirna),graph.getNode(gene));
				e.setAttribute("experiments", r[index.get("Experiments")]);
				e.setAttribute("supportType", r[index.get("Support Type")]);
				e.setAttribute("referenceID", r[index.get("References (PMID)")]);
				
				List<String> list = new ArrayList<String>();
				list.add(mirna);
				foundConnections.add(gene + "\t" + mirna);
				edges.put(gene, list);
				countEdges++;
			}
		}
	}

	private interface Args extends AHelp, AFilesIn, AFilesOut {}
}
